package com.ambitor.ipro.actions;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.struts2.json.annotations.JSON;

import com.ambitor.grass.sql.dao.SuperDao;
import com.ambitor.grass.sql.dao.impl.SuperDaoImpl;
import com.ambitor.grass.util.data.DataMap;
import com.ambitor.grass.util.data.DatasetList;
import com.ambitor.grass.util.data.IData;
import com.ambitor.grass.util.data.IDataset;
import com.ambitor.ipro.app.sche.InstallerHelper;
import com.ambitor.ipro.entities.Result;
import com.ambitor.ipro.entities.TradeState;
import com.ambitor.ipro.exceptions.ProException;
import com.ambitor.ipro.labelParser.IntellLabelParser;
import com.ambitor.ipro.labelParser.IntellLabelParserFactory;
import com.ambitor.ipro.service.InstallService;
import com.ambitor.ipro.service.TopService;
import com.ambitor.ipro.util.Constants;
import com.ambitor.ipro.util.DateUtil;
import com.ambitor.ipro.util.ResultCode;
import com.ambitor.ipro.util.SkyenccUtil;
import com.ambitor.ipro.util.StringUtil;
import com.ambitor.ipro.util.Utils;
import com.taobao.api.domain.Item;

public class InstallAction extends BaseAction {

	private transient Map<String, String> ipro;

	private transient TopService topService;

	private transient SuperDao superDao;

	private Result result = new Result();

	private static final long serialVersionUID = -5524240766566189217L;

	public InstallAction() throws SQLException {
		superDao = new SuperDaoImpl(pd.getConn());
		topService = new TopService(Constants.EVN_SWITCH,
				Constants.APP_KEY_IPROMOTION, Constants.APP_SECRET_IPROMOTION);
	}

	@JSON(serialize = false)
	public Map<String, String> getIpro() {
		return ipro;
	}

	public void setIpro(Map<String, String> ipro) {
		this.ipro = ipro;
	}

	public Result getResult() {
		return result;
	}

	public void setResult(Result result) {
		this.result = result;
	}

	@SuppressWarnings("unchecked")
	public String install() {
		IData progressData = new DataMap();
		progressData.put("code", "1");
		progressData.put("msg", "开始安装...");
		progressData.put("percent", 5);
		pd.setSessionAttribute(Constants.SESSION_INSTL_PROGS, progressData);

		InstallService installService = new InstallService(superDao);
		try {
			IData iproMap = new DataMap(ipro);
			String installPlaces = ipro.get("install_place");
			IDataset userPros = buildUserPros(iproMap);
			IDataset savedUserPros = new DatasetList();
			for (int i = 0; i < userPros.size(); i++) {
				IData userPro = userPros.getData(i);
				IData savedUserPro = installService.saveUserPro(userPro);// 保存推广配置
				savedUserPros.add(savedUserPro);
			}

			// 不管安装几个位置，只加一个批次，pro_id填第一个的
			String batchId = installService.saveTrdeProBatch(savedUserPros
					.getData(0), installPlaces);

			try {
				logTaskStart(batchId);
				int[] res = _install(savedUserPros, batchId, installPlaces);
				logTaskEnd(batchId, res);
			} catch (ProException e) {
				logTaskQuit(batchId, e);
				throw e;
			}
		} catch (Exception e) {
			logger.error(pd.getTopNick() + "保存user_pro出现异常", e);
			result.setCode(ResultCode.ERROR);
			result.setMsg(e.getMessage());

			progressData.put("code", "-1");
			pd.setSessionAttribute(Constants.SESSION_INSTL_PROGS, progressData);

			return SUCCESS;
		}

		// 暂时不安装安装计数器了
		result.setCode(ResultCode.SUCCESS);
		result.setMsg("安装成功");
		pd.RemoveSessionAttribute(Constants.PRO_SETTING);
		return SUCCESS;
	}

	@SuppressWarnings("unchecked")
	private IDataset buildUserPros(IData iproMap) {
		IDataset userPros = new DatasetList();
		IData userPro = buildUserPro(iproMap);
		String installPlaces = iproMap.getString("install_place");
		if (StringUtils.isBlank(installPlaces)) {
			installPlaces = "top_1";
		}

		String[] placeArray = installPlaces.trim().split(",");
		for (String place : placeArray) {
			IData newUserPro = new DataMap(userPro);
			newUserPro.put("INSTALL_PLACE", place);
			userPros.add(newUserPro);
		}
		return userPros;
	}

	@SuppressWarnings("unchecked")
	private IData buildUserPro(IData iproMap) {
		IData userPro = new DataMap();
		userPro.put("USER_ID", pd.getTopUserId());
		userPro.put("NICK", pd.getTopNick());
		userPro.put("INSTALL_SETTING", iproMap.getString("promote_radio"));
		userPro.put("CATEGORIES", iproMap.getString("install_cids"));
		userPro.put("ITEM_CATEGORIES", iproMap.getString("item_install_cids"));
		userPro.put("INSTALL_IIDS", iproMap.getString("to_promote_iids"));
		userPro.put("STYLE_ID", iproMap.getString("style_id"));
		userPro.put("TITLE", iproMap.getString("title"));

		String isIntellClose = iproMap.getString("is_intell_close");
		if ("INTELL_OFF".equalsIgnoreCase(isIntellClose)) {
			userPro.put("INTELL_NUM", 0);
		} else {
			Integer[] intellIntegerNums = StringUtil.strArrayToIntArray(iproMap
					.getString("intell_nums").split(","));
			int intellNums = StringUtil.sum(intellIntegerNums);
			userPro.put("INTELL_NUM", intellNums);
		}

		if (userPro.getInt("INTELL_NUM") <= 0) {
			userPro.put("INTELL_SETTING", "");
			userPro.put("FREQUENCY", -1);
		} else {
			String[] intellLables = iproMap.getString("intell_labels").split(
					",");
			String[] intellNums = iproMap.getString("intell_nums").split(",");
			StringBuilder intellSetting = new StringBuilder();
			for (int i = 0; i < intellNums.length; i++) {
				if (StringUtils.isBlank(intellNums[i])
						|| "0".equals(StringUtils.trimToEmpty(intellNums[i]))) {
					continue;
				} else {
					intellSetting.append(intellLables[i] + ":" + intellNums[i]
							+ ",");
				}
			}
			String intellSettingStr = StringUtil.trimSuffix(intellSetting
					.toString(), ",");

			userPro.put("INTELL_SETTING", intellSettingStr);
			userPro.put("FREQUENCY", iproMap.getString("intell_frequency"));
		}

		if (StringUtils.isBlank(iproMap.getString("be_promoted_iids"))) {
			userPro.put("STATIC_NUM", 0);
			userPro.put("STATIC_SETTING", "");
		} else {
			int staticNum = (iproMap.getString("be_promoted_iids").split(",")).length;
			userPro.put("STATIC_NUM", staticNum);
			userPro
					.put("STATIC_SETTING", iproMap
							.getString("be_promoted_iids"));
		}
		return userPro;
	}

	@SuppressWarnings("unchecked")
	private int[] _install(IDataset userPros, String batchId,
			String installPlaces) throws ProException {
		IData userPro;
		try {
			userPro = userPros.getData(0);
		} catch (Exception e) {
			throw new ProException(e.toString());
		}
		// 要装到哪些宝贝上
		List<String> installIids = this.getInstallIids(userPro);
		if (installIids == null || installIids.size() == 0) {
			throw new ProException(ResultCode.BUSSINESS_EXCEPTION, "获取待安装的宝贝为空");
		}

		// 获取userStyle
		IData param = new DataMap();
		param.put("STYLE_ID", userPro.getString("STYLE_ID"));
		IData userStyle;
		try {
			userStyle = superDao.queryByPK("TF_P_USER_STYLE", param);
		} catch (Exception e) {
			throw new ProException(e.toString());
		}

		// 获取静态推广宝贝
		List<Item> staticItemList = getStaticItemsToBePromoted(userPro);

		// 获取动态态推广宝贝
		List<Item> intellItemList = getIntellItemsToBePromoted(userPro,
				installIids.get(0));

		InstallerHelper installerHelper = new InstallerHelper(superDao,
				topService, pd.getUserSession(), userPro, userStyle);

		int installed = 0; // 已经尝试安装的数量
		int errorNum = 0; // 其中出错的个数
		boolean isIntellLabelSimple = Utils.isIntellLabelSimple(userPro
				.getString("INTELL_SETTING"));
		IDataset tradePros = new DatasetList();

		// simple标签，每个宝贝装的内容都一样
		if (isIntellLabelSimple && staticItemList.size() == 0
				&& intellItemList.size() == 0) {// 假如不是simple标签，下次可能还不为空，所以不抛出异常
			throw new ProException(ResultCode.BUSSINESS_EXCEPTION, "获取待推广的宝贝为空");
		}

		List<Item> allItems = installerHelper.buildAllItemsToBePromoted(
				staticItemList, intellItemList);
		List<String> proModules = installerHelper.buildPromHTML(allItems,
				installPlaces.split(","));

		for (String installIid : installIids) {
			IData tradePro = new DataMap();
			tradePro.put("BATCH_ID", batchId);
			tradePro.put("IID", installIid);
			tradePro.put("PLACE", userPro.getString("INSTALL_PLACE"));
			tradePro.put("LOG_TIME", DateUtil.formatDate(new Date()));
			tradePro.put("EXP_TYPE", null);
			tradePro.put("EXP_DESC", null);
			tradePro.put("EXP_CODE", null);
			tradePro.put("EXP_MSG", null);
			tradePro.put("EXP_SUB_CODE", null);
			tradePro.put("EXP_SUB_MSG", null);
			try {
				if (isIntellLabelSimple == false) {
					intellItemList = getIntellItemsToBePromoted(userPro,
							installIid);
					if (staticItemList.size() == 0
							&& intellItemList.size() == 0) {
						throw new ProException(ResultCode.BUSSINESS_EXCEPTION,
								"获取待推广的宝贝为空");
					}
					allItems = installerHelper.buildAllItemsToBePromoted(
							staticItemList, intellItemList);
					proModules = installerHelper.buildPromHTML(allItems,
							installPlaces.split(","));
				}
				installerHelper.installInTaobao(installIid, proModules);
				tradePro.put("TRADE_STATE", Constants.FLAG_YES);// 成功
				// tradePro.put("PRO_MODULE", proModules.get(0));// 只保存第一个位置的
			} catch (ProException e) {
				tradePro.put("TRADE_STATE", Constants.FLAG_NO);// 失败
				tradePro.put("EXP_TYPE", e.getType());
				tradePro.put("EXP_DESC", e.getDesc());
				tradePro.put("EXP_CODE", e.getCode());
				tradePro.put("EXP_MSG", e.getMsg());
				tradePro.put("EXP_SUB_CODE", e.getSubCode());
				tradePro.put("EXP_SUB_MSG", e.getSubMsg());
				errorNum++;
				continue;
			} finally {
				installed++;
				tradePros.add(tradePro);
				String progressInfo = "一共要安装到" + installIids.size() + "个宝贝上，"
						+ "已经完成" + installed + "个，其中错误" + errorNum + "个";
				double percent = (installed * 1D / installIids.size()) * 100;
				IData progressData = new DataMap();
				if (installed < installIids.size()) {
					progressData.put("code", "1");
					progressData.put("msg", progressInfo);
				} else {
					progressData.put("code", "0");
					progressData.put("msg", progressInfo);
				}
				progressData.put("percent", percent);
				pd.setSessionAttribute(Constants.SESSION_INSTL_PROGS,
						progressData);
			}
		}

		try {
			// updateItemPros(installIids, userPros);
			insertTradePros(batchId, tradePros);
		} catch (Exception exp) {
			logger.error("新增tradePro日志或更新item_pro出现数据库异常", exp);
		}

		return new int[] { installIids.size(), errorNum };
	}

	@SuppressWarnings("unchecked")
	private List<String> getInstallIids(IData userPro) throws ProException {
		String installSetting = userPro.getString("INSTALL_SETTING");
		String sessionId = pd.getTopSessionId();
		String nick = pd.getTopNick();

		List<String> iidList = new ArrayList<String>();
		if ("custom".equals(installSetting)) {
			String staticSetting = userPro.getString("INSTALL_IIDS");
			for (String iid : staticSetting.split(",")) {
				iidList.add(iid);
			}
		} else if ("someCategory".equals(installSetting)) {
			String sellerCids = userPro.getString("CATEGORIES");
			List<Item> itemList = topService.getOnSaleItemsOfSpecificSellerCat(
					sessionId, nick, sellerCids);
			for (Item item : itemList) {
				iidList.add(item.getNumIid().toString());
			}
		} else if ("itemCategory".equals(installSetting)) {
			String itemCids = userPro.getString("ITEM_CATEGORIES");
			List<Item> itemList = topService.getOnSaleItemsOfSpecificItemCat(
					sessionId, nick, itemCids);
			for (Item item : itemList) {
				iidList.add(item.getNumIid().toString());
			}
		} else if ("onSale".equals(installSetting)) {
			List<Item> itemList = topService.getOnSaleItems(sessionId, nick);
			for (Item item : itemList) {
				iidList.add(item.getNumIid().toString());
			}
		} else if ("all".equals(installSetting)) {
			List<Item> itemList = topService.getAllItems(sessionId, nick);
			for (Item item : itemList) {
				iidList.add(item.getNumIid().toString());
			}
		}
		return iidList;
	}

	private List<Item> getStaticItemsToBePromoted(IData userPro)
			throws ProException {
		List<Item> staticItemList = new ArrayList<Item>();
		int staticNum = userPro.getInt("STATIC_NUM");
		if (staticNum <= 0)
			return staticItemList;
		String staticSetting = userPro.getString("STATIC_SETTING");
		String[] staticSettingArray = staticSetting.split(",");
		String sessionId = pd.getTopSessionId();
		String nick = pd.getTopNick();
		int erroNum = 0;
		for (String iid : staticSettingArray) {
			Item item = null;
			try {
				item = topService.getItem(sessionId, nick, iid);
			} catch (ProException e) {
				erroNum++;
				logger.warn(e.getMessage());
				if (erroNum == staticSettingArray.length) {
					String desc = "获取" + erroNum + "个静态推广宝贝全部出错";
					throw new ProException(ResultCode.BUSSINESS_EXCEPTION,
							desc, e.getCode(), e.getMsg(), e.getSubCode(), e
									.getSubMsg());
				}
			}
			if (item != null)
				staticItemList.add(item);
		}
		return staticItemList;
	}

	@SuppressWarnings("unchecked")
	private List<Item> getIntellItemsToBePromoted(IData userPro,
			String installIid) throws ProException {
		List<Item> intellItemList = new ArrayList<Item>();
		int intellNum = userPro.getInt("INTELL_NUM");
		if (intellNum <= 0) {
			return intellItemList;
		}
		int staticNum = userPro.getInt("STATIC_NUM");
		String[] intellSettingArray = userPro.getString("INTELL_SETTING")
				.trim().split(",");
		if (intellSettingArray.length == 1) { // 当前web前台只能设置1个推广规则，下面代码肯定运行
			String[] labelStr = intellSettingArray[0].split(":");
			String intellLabel = labelStr[0];
			int minSumNum = intellNum + staticNum;// 取在最大重合的item的情况下也足够的item数量
			IntellLabelParser parser = IntellLabelParserFactory.instance(
					intellLabel, superDao, topService, pd.getUserSession(),
					installIid, minSumNum);
			intellItemList = parser.parse();
		}
		return intellItemList;
	}

	/**
	 * @deprecated
	 * @param installIids
	 * @param userPros
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public void updateItemPros(List<String> installIids, IDataset userPros)
			throws Exception {
		IDataset itemPros = new DatasetList();
		for (int i = 0; i < userPros.size(); i++) {
			for (String installIid : installIids) {
				IData userPro = userPros.getData(i);
				IData itemPro = new DataMap();
				itemPro.put("INSTALL_IID", installIid);
				String installPlace = userPro.getString("INSTALL_PLACE");
				itemPro.put("INSTALL_PLACE", installPlace);
				itemPro.put("USER_ID", pd.getTopUserId());
				itemPro.put("PRO_ID", userPro.getString("PRO_ID"));
				itemPros.add(itemPro);
			}
			try {
				superDao.delete("TF_P_ITEM_PRO", itemPros);
				superDao.insert("TF_P_ITEM_PRO", itemPros);
			} catch (Exception exp) {
				logger.warn("保存TF_P_ITEM_PRO出现数据库异常", exp);
			}
		}
	}

	// 新增安装日志表
	@SuppressWarnings("unchecked")
	private void insertTradePros(String batchId, IDataset tradePros)
			throws Exception {
		IDataset params = new DatasetList();
		for (int i = 0; i < tradePros.size(); i++) {
			IData tradePro = tradePros.getData(i);
			IData param = new DataMap();
			param.put("BATCH_ID", batchId);
			param.put("IID", tradePro.getString("IID"));
			params.add(param);
		}
		String sql = "delete from TL_P_TRADE_PRO where batch_id = :BATCH_ID "
				+ "  and iid = :IID";
		superDao.getBaseDao().executeBatch(sql, params);
		superDao.insert("TL_P_TRADE_PRO", tradePros);
	}

	@SuppressWarnings("unchecked")
	protected void logTaskStart(String batchId) {
		IData updateTask = new DataMap();
		updateTask.put("BATCH_ID", batchId);
		updateTask.put("TRADE_STATE", TradeState.BEING_EXECUTE);// 开始执行
		updateTask.put("EXEC_TIME", SkyenccUtil.formatDate(new Date()));// 开始执行时间
		try {
			superDao.update("TF_P_TRADE_PRO_BATCH", updateTask);
		} catch (Exception e) {
			logger.error("更新BATCH_ID=" + batchId + "的工单的开始执行时间出现错误", e);
		}
	}

	@SuppressWarnings("unchecked")
	private void logTaskQuit(String batchId, ProException e) {
		logger.warn("预执行BATCH_ID=" + batchId + "的工单时出现错误，退出预执行。");
		logger.warn(e.toString(), e);
		IData tradeProBatchLog = new DataMap();
		tradeProBatchLog.put("BATCH_ID", batchId);
		tradeProBatchLog.put("LOG_TIME", SkyenccUtil.formatDate(new Date()));
		tradeProBatchLog.put("EXP_TYPE", e.getType());
		tradeProBatchLog.put("EXP_DESC", e.getDesc());
		tradeProBatchLog.put("EXP_CODE", e.getCode());
		tradeProBatchLog.put("EXP_MSG", e.getMsg());
		tradeProBatchLog.put("EXP_SUB_CODE", e.getSubCode());
		tradeProBatchLog.put("EXP_SUB_MSG", e.getSubMsg());
		try {
			superDao.delete("TL_P_TRADE_PRO_BATCH", tradeProBatchLog);
			superDao.insert("TL_P_TRADE_PRO_BATCH", tradeProBatchLog);
		} catch (Exception exp) {
			logger.warn("保存TL_P_TRADE_PRO_BATCH出现数据库异常", exp);
		}

		IData updateTask = new DataMap();
		updateTask.put("BATCH_ID", batchId);
		updateTask.put("TRADE_STATE", TradeState.QUIT_EXECUTE);// 执行终止
		try {
			superDao.update("TF_P_TRADE_PRO_BATCH", updateTask);
		} catch (Exception exp) {
			logger.error("更新BATCH_ID=" + batchId + "的工单到中止状态出现异常", exp);
		}
	}

	@SuppressWarnings("unchecked")
	private void logTaskEnd(String batchId, int[] result) {
		IData updateTask = new DataMap();
		updateTask.put("BATCH_ID", batchId);
		updateTask.put("IID_SUM_NUM", result[0]);
		updateTask.put("IID_ERROR_NUM", result[1]);

		if (updateTask.getInt("IID_ERROR_NUM", -1) == 0) {
			updateTask.put("TRADE_STATE", TradeState.EXECUTED_SUCCESS);// 执行成功结束
			updateTask.put("FINISH_TIME", SkyenccUtil.formatDate(new Date()));// 执行成功时间
		} else {
			updateTask.put("TRADE_STATE", TradeState.EXECUTED_EXIST_FAIL);// 执行结束部分成功
		}
		try {
			superDao.update("TF_P_TRADE_PRO_BATCH", updateTask);
		} catch (Exception e) {
			logger.error("更新BATCH_ID=" + batchId + "的工单的完工情况出现错误", e);
		}

		if (updateTask.getInt("IID_ERROR_NUM", -1) == 0) {
			moveTradeProBatchToHistory(batchId);
		}
	}

	@SuppressWarnings("unchecked")
	private void moveTradeProBatchToHistory(String batchId) {
		IData updateTask = new DataMap();
		updateTask.put("BATCH_ID", batchId);
		try {
			IData tradeProBatch = superDao.queryByPK("TF_P_TRADE_PRO_BATCH",
					updateTask);
			superDao.delete("TF_PH_TRADE_PRO_BATCH", tradeProBatch);
			superDao.insert("TF_PH_TRADE_PRO_BATCH", tradeProBatch);
			superDao.delete("TF_P_TRADE_PRO_BATCH", tradeProBatch);
		} catch (Exception e) {
			logger.error("把BATCH_ID=" + batchId + "的工单移动到历史表出现错误", e);
		}
	}
}